#include "applauncher.h"
AppLauncher::AppLauncher(QWidget *parent) : PreventCloseWindow(parent)
{
	setAttribute(Qt::WA_TranslucentBackground);
	setWindowFlags(Qt::FramelessWindowHint | Qt::Tool);
	setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
	centralWidget = new QWidget(this);
	QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);
	mainLayout->setContentsMargins(0, 0, 0, 0);
	mainLayout->addStretch();
	QPushButton *settingsButton = new QPushButton("设置", this);
	settingsButton->setFixedSize(100, 50);
	mainLayout->addWidget(settingsButton);
	QWidget *gridContainer = new QWidget(centralWidget);
	gridLayout = new QGridLayout(gridContainer);
	gridLayout->setContentsMargins(0, 0, 0, 0);
	gridLayout->setSpacing(0);
	gridLayout->setAlignment(Qt::AlignBottom | Qt::AlignRight);
	centralWidget->setContentsMargins(0, 0, 0, 0);
	mainLayout->addWidget(gridContainer);
	setCentralWidget(centralWidget);
	connect(settingsButton, &QPushButton::clicked, this, [this] {
		SettingsWindow->loadConfig();
		SettingsWindow->show();
		SettingsWindow->raise();
		SettingsWindow->activateWindow();
	});
	QFile configFile("applauncher.json");
	if (!configFile.open(QIODevice::ReadOnly)) {
		QJsonArray defaultConfig =
			{QJsonObject{{"name", "希沃白板5"}, {"type", "app"}, {"path", "C:\\Program Files (x86)\\Seewo\\EasiNote5\\swenlauncher\\swenlauncher.exe"}}, QJsonObject{{"name", "希沃视频展台"}, {"type", "app"}, {"path", "C:\\Program Files (x86)\\Seewo\\EasiCamera\\sweclauncher\\sweclauncher.exe"}}, QJsonObject{{"name", "希沃轻白板"}, {"type", "app"}, {"path", "C:\\Program Files (x86)\\Seewo\\EasiNote5C\\swenlauncher\\swenlauncher.exe"}}, QJsonObject{{"name", "随机点名"}, {"type", "internal"}, {"command", "random_call"}, {"icon", ":/img/random_call.svg"}}, QJsonObject{{"name", "此电脑"}, {"type", "folder"}, {"path", "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}"}, {"icon", ":/img/computer.png"}}, QJsonObject{{"name", "D盘"}, {"type", "folder"}, {"path", "D:"}}, QJsonObject{{"name", "打开U盘"}, {"type", "internal"}, {"command", "open_usb"}, {"icon", ":/img/open_usb.png"}}, QJsonObject{{"name", "弹出U盘"}, {"type", "internal"}, {"command", "eject_usb"}, {"icon", ":/img/eject_usb.png"}}};
		if (configFile.open(QIODevice::WriteOnly)) {
			QJsonDocument doc(defaultConfig);
			configFile.write(doc.toJson());
			configFile.close();
		}
		configItems = defaultConfig;
	} else {
		QByteArray data = configFile.readAll();
		QJsonDocument configDoc(QJsonDocument::fromJson(data));
		configItems = configDoc.array();
		configFile.close();
	}
	int row = 0, col = 0;
	for (const QJsonValue &itemValue : configItems) {
		QJsonObject item = itemValue.toObject();
		QString name = item["name"].toString(), iconPath = item["icon"].toString();
		if (iconPath.isEmpty()) iconPath = item["path"].toString();
		QPushButton *button = new QPushButton(name, centralWidget);
		button->setProperty("itemData", itemValue);
		QIcon icon;
		if (iconPath.startsWith(":/")) icon = QIcon(iconPath);
		else if (iconPath.isEmpty() || !QFile::exists(iconPath)) icon = QIcon();
		else {
			QFileInfo fileInfo(iconPath);
			if (QStringList{"png", "jpg", "jpeg", "bmp", "gif", "svg"}.contains(fileInfo.suffix().toLower())) {
				QPixmap pixmap(iconPath);
				if (!pixmap.isNull()) icon = QIcon(pixmap.scaled(64, 64, Qt::KeepAspectRatio));
				else icon = QIcon();
			} else {
				QIcon tempIcon = QFileIconProvider().icon(fileInfo);
				icon = !tempIcon.isNull() ? tempIcon : QIcon();
			}
		}
		if (!icon.isNull()) {
			button->setIcon(icon);
			button->setIconSize(QSize(64, 64));
		}
		button->setFixedSize(200, 100);
		connect(button, &QPushButton::clicked, this, &AppLauncher::handleItemClicked);
		buttonOriginalTexts[button] = name;
		gridLayout->addWidget(button, row, col);
		col++;
		if (col >= maxColumns) {
			col = 0;
			row++;
		}
	}
	random_window = new RandomStudent();
	random_window->close();
	desktopBall = new DesktopBall();
	connect(desktopBall, &DesktopBall::clicked, this, [this]() {
		activateWindow();
		raise();
		show();
	});
	desktopBall->show();
	timetableWidget = new UnclosableListWidget(nullptr);
	timetableWidget->setObjectName("timetable");
	setStyleSheet(R"(*{font-size: 20px;}QPushButton{color: #000000;background-color: qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgba(55, 131, 255, 64), stop:1 rgba(165, 191, 214, 64));border-radius: 25px;}QPushButton:hover {background-color: #E0E0FF;}QPushButton:disabled {background-color: #80ff80;}#timetable {background-color: rgba(0, 0, 0, 0);color: #ffffff;}QListWidget {font-size: 29pt;border: none;})");
	QFont font(MAINFT, 27);
	timetableWidget->setParent(nullptr);
	timetableWidget->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnBottomHint | Qt::WindowTransparentForInput);
	timetableWidget->setAttribute(Qt::WA_TranslucentBackground);
	timetableWidget->setStyleSheet("color: #ffffff;background-color: rgba(0,0,0,0);border: none;");
	timetableWidget->setFont(font);
	timetableWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	timetableWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	timetableWidget->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
	timetableWidget->show();
	adjustSize();
	SettingsWindow = new ClassroomComputerSettings();
	SettingsWindow->hide();
	refreshTimer = new QTimer(this);
	connect(refreshTimer, &QTimer::timeout, this, &AppLauncher::refreshGUI);
	refreshTimer->start(3000);
	refreshGUI();
}
AppLauncher::~AppLauncher()
{
	if (deviceDialog) delete deviceDialog;
	if (desktopBall) delete desktopBall;
}
void AppLauncher::onDeviceDialogRejected()
{
	if (currentTriggerButton) {
		if (buttonTimers.contains(currentTriggerButton)) {
			buttonTimers[currentTriggerButton]->stop();
			buttonTimers[currentTriggerButton]->deleteLater();
			buttonTimers.remove(currentTriggerButton);
		}
		currentTriggerButton->setText(buttonOriginalTexts[currentTriggerButton]);
		currentTriggerButton->setEnabled(true);
		buttonAnimationIndices.remove(currentTriggerButton);
	}
}
void AppLauncher::showMessageOnButton(QPushButton *button, const QString &message)
{
	if (buttonTimers.contains(button)) {
		buttonTimers[button]->stop();
		buttonTimers[button]->deleteLater();
		buttonTimers.remove(button);
	}
	button->setText(message);
	button->setEnabled(false);
	QTimer::singleShot(3000, this, [this, button] {
		button->setText(buttonOriginalTexts[button]);
		button->setEnabled(true);
	});
}
void AppLauncher::restoreButtonAfterDelay(QPushButton *button, int delayMs)
{
	QTimer::singleShot(delayMs, this, [this, button] {
		if (buttonTimers.contains(button)) {
			buttonTimers[button]->stop();
			buttonTimers[button]->deleteLater();
			buttonTimers.remove(button);
		}
		button->setText(buttonOriginalTexts[button]);
		button->setEnabled(true);
	});
}
void AppLauncher::handleItemClicked()
{
	QPushButton *button = qobject_cast<QPushButton *>(sender());
	if (!button) return;
	button->setEnabled(false);
	buttonOriginalTexts[button] = button->text();
	buttonAnimationIndices[button] = 0;
	button->setText(spinnerFrames[0]);
	QTimer *timer = new QTimer(this);
	connect(timer, &QTimer::timeout, this, [this, button]() {
		if (!buttonAnimationIndices.contains(button)) return;
		int &index = buttonAnimationIndices[button];
		index = (index + 1) % spinnerFrames.size();
		button->setText("加载中" + spinnerFrames[index]);
	});
	timer->start(40);
	buttonTimers[button] = timer;
	currentTriggerButton = button;
	QTimer::singleShot(0, this, [this, button]() {
		QJsonObject item = button->property("itemData").toJsonObject();
		QString type = item["type"].toString();
		QString path = item["path"].toString();
		QString command = item["command"].toString();
		QString resultMessage;
		bool success = true;
		try {
			if (type == "app") {
				if (!QProcess::startDetached(path)) throw QString("启动失败: %1").arg(path);
			} else if (type == "file" || type == "folder") {
				if (!QDesktopServices::openUrl(QUrl::fromLocalFile(path))) throw QString("打开失败: %1").arg(path);
			} else if (type == "internal") {
				if (command == "random_call") {
					random_window->show();
					random_window->move(screenx + (screenw - random_window->width()) / 2, screeny + (screenh - random_window->height()) / 2);
				}
				if (command == "open_usb") {
					currentDrives = getRemovableDrives();
					if (currentDrives.isEmpty()) throw QString("未检测到U盘");
					else if (currentDrives.size() == 1) {
#ifdef Q_OS_WIN
						QDesktopServices::openUrl(QUrl::fromLocalFile(QString("%1:").arg(currentDrives.first().second)));
#endif
					} else {
						isEjectAction = false;
						showDeviceSelectionDialog("请选择要打开的U盘", "打开");
					}
				} else if (command == "eject_usb") {
					currentDrives = getRemovableDrives();
					if (currentDrives.isEmpty()) throw QString("未检测到U盘");
					else {
						isEjectAction = true;
						showDeviceSelectionDialog("请选择要弹出的设备", "弹出");
					}
				}
			}
		} catch (const QString &error) {
			success = false;
			resultMessage = error;
		}
		if (!success) showMessageOnButton(button, resultMessage);
		else if (command != "open_usb" && command != "eject_usb" || (command == "open_usb" && currentDrives.size() == 1) || (command == "eject_usb" && currentDrives.size() == 1)) restoreButtonAfterDelay(button, 3000);
	});
}
QPair<bool, QString> AppLauncher::ejectRemovableDrive(char driveLetter)
{
	if (ejectRemovableDriveInternal(driveLetter)) return qMakePair(true, QString("设备 %1:\n已安全弹出").arg(driveLetter));
	if (QMessageBox::warning(this, "U盘占用", QString("设备 %1: 可能被占用, 无法安全弹出!\n是否尝试强制弹出？").arg(driveLetter), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) return qMakePair(false, QString("取消强制弹出 %1").arg(driveLetter));
	if (forceEjectRemovableDrive(driveLetter)) return qMakePair(true, QString("设备 %1:\n已强制弹出").arg(driveLetter));
	return qMakePair(false, QString("无法弹出 %1").arg(driveLetter));
}
void AppLauncher::showDeviceSelectionDialog(const QString &title, const QString &action)
{
	if (currentDrives.isEmpty()) {
		showMessageOnButton(currentTriggerButton, "没有检测到U盘");
		return;
	}
	if (deviceDialog) delete deviceDialog;
	deviceDialog = new QDialog(this);
	deviceDialog->setWindowTitle(title);
	QScrollArea *scrollArea = new QScrollArea(deviceDialog);
	QWidget *scrollWidget = new QWidget(scrollArea);
	QVBoxLayout *scrollLayout = new QVBoxLayout(scrollWidget);
	scrollLayout->setContentsMargins(0, 0, 0, 0);
	scrollLayout->setSpacing(0);
	scrollArea->setWidgetResizable(true);
	scrollArea->setWidget(scrollWidget);
	scrollArea->setFrameShape(QFrame::NoFrame);
	for (const auto &drive : currentDrives) {
		QPushButton *btn = new QPushButton(drive.first, scrollWidget);
		btn->setProperty("driveLetter", drive.second);
		btn->setFixedHeight(30);
		connect(btn, &QPushButton::clicked, this, [this] {
			if (!deviceDialog) return;
			QPushButton *btn = qobject_cast<QPushButton *>(sender());
			if (!btn) return;
			char driveLetter = btn->property("driveLetter").toChar().toLatin1();
			deviceDialog->accept();
			if (isEjectAction) {
				auto result = ejectRemovableDrive(driveLetter);
				showMessageOnButton(currentTriggerButton, result.second);
			} else {
				QDesktopServices::openUrl(QUrl::fromLocalFile(QString("%1:").arg(driveLetter)));
				restoreButtonAfterDelay(currentTriggerButton, 3000);
			}
		});
		scrollLayout->addWidget(btn);
	}
	int maxHeight = QGuiApplication::primaryScreen()->geometry().height() / 2;
	deviceDialog->setMaximumHeight(maxHeight);
	QVBoxLayout *mainLayout = new QVBoxLayout(deviceDialog);
	mainLayout->addWidget(scrollArea);
	deviceDialog->setMinimumSize(200, 100);
	deviceDialog->setLayout(mainLayout);
	deviceDialog->adjustSize();
	connect(deviceDialog, &QDialog::rejected, this, &AppLauncher::onDeviceDialogRejected);
	deviceDialog->exec();
}
void AppLauncher::refreshGUI()
{
	m_startTimes.clear();
	m_endTimes.clear();
	m_coursesTitles.clear();
	m_courses.clear();
	g_currentClassInfo = CurrentClassInfo();
	QFile file("timetable.csv");
	if (!file.open(QIODevice::ReadOnly)) {
		timetableWidget->clear();
		timetableWidget->addItem("课程表出错: " + file.errorString());
	} else {
		QTextStream in(&file);
		QStringList headers = in.readLine().split(',');
		int weekdayCol = QDate::currentDate().dayOfWeek() + 2;
		if (weekdayCol < 3 || weekdayCol > 9) weekdayCol = 3;
		while (!in.atEnd()) {
			QStringList parts = in.readLine().split(',');
			if (parts.size() < 10) continue;
			m_startTimes << QTime::fromString(parts[0], "hh:mm");
			m_endTimes << QTime::fromString(parts[1], "hh:mm");
			m_coursesTitles << parts[2];
			m_courses << parts[weekdayCol];
		}
		file.close();
		QFile tempFile("temp.csv");
		if (tempFile.exists()) {
			QFileInfo fileInfo(tempFile);
			if (fileInfo.lastModified().date() != QDate::currentDate()) {
				tempFile.remove();
			} else if (tempFile.open(QIODevice::ReadOnly)) {
				QTextStream in(&tempFile);
				QStringList tempCourses = in.readAll().split('\n');
				tempFile.close();
				while (!tempCourses.isEmpty() && tempCourses.last().trimmed().isEmpty()) tempCourses.removeLast();
				if (tempCourses.size() == m_courses.size()) {
					m_courses.clear();
					foreach (QString course, tempCourses) m_courses << course.trimmed();
				} else {
					tempFile.remove();
					QMessageBox::warning(this, "课程表", "临时课表课时数不匹配，已自动删除\n");
				}
			}
		}
		timetableWidget->clear();
		QTime currentTime = QTime::currentTime();
		for (int i = 0; i < m_startTimes.size(); ++i) {
			if (m_courses[i] == "-") continue;
			if (currentTime >= m_startTimes[i] && currentTime <= m_endTimes[i]) {
				g_currentClassInfo.isInClass = true;
				g_currentClassInfo.subject = m_courses[i];
				g_currentClassInfo.startTime = m_startTimes[i];
				g_currentClassInfo.endTime = m_endTimes[i];
				break;
			}
		}
		for (int i = 0; i < m_courses.size(); ++i) {
			QString text = QString("%1 %2-%3 %4").arg(m_coursesTitles[i]).arg(m_startTimes[i].toString("hh:mm")).arg(m_endTimes[i].toString("hh:mm")).arg(m_courses[i]);
			QListWidgetItem *item = new QListWidgetItem(text);
			QTime current = QTime::currentTime();
			QFont font(MAINFT, 27);
			if (m_courses.value(i) == "-") {
				item->setSizeHint(QSize(0, 0));
				item->setForeground(QColor(0, 0, 0, 0));
				continue;
			}
			if (current >= m_startTimes[i] && current <= m_endTimes[i]) {
				font.setBold(true);
				font.setUnderline(true);
				item->setBackground(QColor(0, 255, 0));
			} else if (current > m_endTimes[i]) {
				font.setItalic(true);
				font.setStrikeOut(true);
			} else item->setBackground(QColor(0, 128, 255, 64));
			item->setFont(font);
			timetableWidget->addItem(item);
		}
	}
	int appWidth = qMin(maxColumns * 200, screenw - 100);
	setGeometry(screenx + screenw - appWidth - 50, screeny + screenh - height(), appWidth, qMin((configItems.size() + maxColumns - 1) / maxColumns * 100 + 50, screenh - 100));
	timetableWidget->adjustSize();
	timetableWidget->setFixedHeight(timetableWidget->sizeHint().height());
	timetableWidget->move(screenx + screenw - timetableWidget->width(), screeny);
}
